﻿Imports System.Drawing.Printing
Imports System.IO
Imports System.Xml

Namespace Objects

    ''' <summary>
    ''' Abstracte klasse om af te printen.
    ''' Wordt geïmplementeerd in PrintVerkoopDocument en PrintVerkoopsrapportDocument
    ''' </summary>
    Public MustInherit Class PrintFairShopDocument
        Inherits PrintDocument

        Protected _font As Font
        Protected _gdiPage As Graphics
        Protected _doc As XmlDocument
        Private _pageNumber As Integer = 1

        ''' <summary>
        ''' Soms kunnen niet alle details op een blad. Deze variabele houdt bij welk het volgende af te drukken detail is.
        ''' </summary>
        Protected _indexVolgendAfTeDrukkenDetail As Integer

        Private _printableWidthValue As String
        Private _printableHeightValue As String
        Private _leftMarginValue As String
        Private _topMarginValue As String

#Region "Public property's"

        Public ReadOnly Property Font() As Font
            Get
                Return _font
            End Get
        End Property

        ''' <summary>
        ''' Bruikbare breedte van de pagina
        ''' </summary>
        Public ReadOnly Property PrintableWidth() As Integer
            Get
                If (_printableWidthValue Is Nothing) Then
                    Dim node As XmlNode = _doc.SelectSingleNode("//fairshop/document/@widthInCm")
                    _printableWidthValue = node.Value
                End If
                Return Convert.ToInt32(Convert.ToDouble(_printableWidthValue) * 100 / 2.54) ' cm x 100dpi / (cm/inch) -> 1/100 inch?
            End Get
        End Property

        ''' <summary>
        ''' Hoogte van de pagina in 1/100 inch. 
        ''' Zet deze waarde op -1 indien het papier onbegrensd is, zoals bij de ticketprinter.
        ''' </summary>
        Public ReadOnly Property PrintableHeight() As Integer
            Get
                If (_printableHeightValue Is Nothing) Then
                    Dim node As XmlNode = _doc.SelectSingleNode("//fairshop/document/@heightInCm")
                    _printableHeightValue = node.Value
                End If
                If (_printableHeightValue = "onbegrensd") Then Return -1
                Return Convert.ToInt32(Convert.ToDouble(_printableHeightValue) * 100 / 2.54) ' cm x 100dpi / (cm/inch) -> 1/100 inch?
            End Get
        End Property

        Public ReadOnly Property LeftMargin() As Integer
            Get
                If (_leftMarginValue Is Nothing) Then
                    Dim node As XmlNode = _doc.SelectSingleNode("//fairshop/document/@leftMarginInCm")
                    _leftMarginValue = node.Value
                End If
                Return Convert.ToInt32(Convert.ToDouble(_leftMarginValue) * 100 / 2.54) ' cm x 100dpi / (cm/inch) -> 1/100 inch?
            End Get
        End Property

        Public ReadOnly Property TopMargin() As Integer
            Get
                If (_topMarginValue Is Nothing) Then
                    Dim node As XmlNode = _doc.SelectSingleNode("//fairshop/document/@topMarginInCm")
                    _topMarginValue = node.Value
                End If
                Return Convert.ToInt32(Convert.ToDouble(_topMarginValue) * 100 / 2.54) ' cm x 100dpi / (cm/inch) -> 1/100 inch?
            End Get
        End Property

#End Region

#Region "Constructor/Initialisatie"

        Public Sub New()
            MyBase.New()
            Initialize()
        End Sub

        ''' <summary>
        ''' 
        ''' </summary>
        Private Sub Initialize()
            _doc = New XmlDocument()
            ' sjablonen moeten in de subfolder "Sjablonen" staan
            Dim sjabloonLocatie As String = String.Format("{0}\Sjablonen\{1}", _
                    Path.GetDirectoryName(Application.ExecutablePath), NaamSjabloon)
            _doc.Load(sjabloonLocatie)

            InitializePrinter()
        End Sub

#End Region

#Region "MustOverride"

        Protected MustOverride ReadOnly Property DetailCount() As Integer

        ''' <summary>
        ''' Gebruikt om voor het afdrukken van de footer te weten of die nog op hetzelfde blad kan
        ''' </summary>
        Protected MustOverride ReadOnly Property FooterLineCount() As Integer

        ''' <summary>
        ''' Naam van het flo-document 
        ''' </summary>
        Protected MustOverride ReadOnly Property NaamSjabloon() As String

        Protected MustOverride Sub InitializePrinter()

        ''' <summary>
        ''' Overschrijf deze methode om de hoofding af te drukken
        ''' </summary>
        ''' <param name="top">Bovenkantpositie vanaf waar geprint moet worden</param>
        ''' <returns>Bovenkant-positie van de volgende rij in dpi</returns>
        Protected MustOverride Function PrintHoofding(ByVal top As Integer) As Integer

        ''' <summary>
        ''' Overschrijf deze methode om iets af te drukken bovenaan vervolgpagina's
        ''' </summary>
        ''' <param name="top">Bovenkantpositie vanaf waar geprint moet worden</param>
        ''' <returns>Bovenkant-positie van de volgende rij in dpi</returns>
        Protected MustOverride Function PrintVervolgHoofding(ByVal top As Integer) As Integer

        Protected MustOverride Function PrintDetails(ByVal top As Integer) As Integer

        Protected MustOverride Sub PrintVoettekst(ByVal top As Integer)

        Protected MustOverride Function ShouldPrintPageNumber() As Boolean

#End Region

#Region "Protected en public methods"

        Protected Overloads Overrides Sub OnBeginPrint(ByVal e As PrintEventArgs)
            MyBase.OnBeginPrint(e)
            InitializeFont()
            _pageNumber = 1
            _indexVolgendAfTeDrukkenDetail = 0
        End Sub

        Protected Overloads Overrides Sub OnEndPrint(ByVal e As PrintEventArgs)
            MyBase.OnEndPrint(e)
            _font.Dispose()
        End Sub

        Protected Overloads Overrides Sub OnPrintPage(ByVal e As PrintPageEventArgs)
            MyBase.OnPrintPage(e)
            _gdiPage = e.Graphics

            Dim top As Integer = TopMargin

            If (ShouldPrintPageNumber()) Then
                top = PrintPageNumber(e.PageBounds, top)
            End If

            If (_indexVolgendAfTeDrukkenDetail = 0) Then
                top = PrintHoofding(top)
            Else
                top = PrintVervolgHoofding(top)
            End If

            top = PrintDetails(top)

            Dim laatsteDetailAfgedrukt As Boolean = (_indexVolgendAfTeDrukkenDetail = DetailCount)
            Dim voettekstKanOpDitBlad As Boolean = (top + _font.Height * FooterLineCount < PrintableHeight OrElse Not IsPaginaBeperkt())
            If (laatsteDetailAfgedrukt AndAlso voettekstKanOpDitBlad) Then
                PrintVoettekst(top)
                e.HasMorePages = False
            Else
                e.HasMorePages = True
            End If
            _pageNumber += 1
        End Sub

        Public Function GetBlok(ByVal naam As String) As DocumentBlok
            Dim blokNode As XmlNode = _doc.SelectSingleNode(String.Format("//fairshop/blokken/blok[@naam=""{0}""]", naam))
            Return New DocumentBlok(Me, blokNode)
        End Function

        ''' <summary>
        ''' Methode om alle rijen van een blok af te drukken. Veronderstelt dat de tekst al ingesteld is
        ''' </summary>
        ''' <param name="blok"></param>
        ''' <param name="top">Bovenkantpositie vanaf waar geprint moet worden</param>
        ''' <returns>Verticale positie van de volgende regel op het blad</returns>
        Public Function PrintBlok(ByVal blok As DocumentBlok, ByVal top As Integer) As Integer
            For Each rij As DocumentRij In blok.Rijen
                top = rij.Print(top, _gdiPage)
            Next
            Return top
        End Function

        ''' <summary>
        ''' Methode om een rij af te drukken. Veronderstelt dat de tekst al ingesteld is
        ''' </summary>
        ''' <param name="documentRij"></param>
        ''' <param name="top">Bovenkantpositie vanaf waar geprint moet worden</param>
        ''' <returns>Verticale positie van de volgende regel op het blad</returns>
        Public Function PrintRij(ByVal documentRij As DocumentRij, ByVal top As Integer) As Integer
            Return documentRij.Print(top, _gdiPage)
        End Function

        ''' <summary>
        ''' Geeft een lege string voor de gewone versie en de tekst " - oefenversie" voor de oefenversie
        ''' </summary>
        ''' <returns></returns>
        Protected Function GetTitleSuffix() As String
            If (Utility.IsOefenVersie()) Then
                Return " - oefenversie"
            Else
                Return ""
            End If
        End Function

        Protected Function IsPaginaBeperkt() As Boolean
            Return PrintableHeight > 0
        End Function

        Public Function PrintBarcode(ByVal barcode As String, ByVal top As Integer) As Integer
            ' converteer van 1/100 inch naar mm
            Dim point As PointF = New PointF With { _
                .X = CSng(LeftMargin * 2.54 * 10 / 100), _
                .Y = CSng(top * 2.54 * 10 / 100) _
            }
            Dim ean13 As New Ean13Barcode(barcode)
            ean13.Scale = 1.3F
            ean13.DrawEan13Barcode(_gdiPage, point)
            Return top + CInt(ean13.Height * ean13.Scale * 100 / 10 / 2.54) ' terug van mm naar 1/100 inch
        End Function

#End Region

#Region "Private methods"

        Private Sub InitializeFont()
            Dim fontNode As XmlNode = _doc.SelectSingleNode("//document/@font")
            Dim fontSizeNode As XmlNode = _doc.SelectSingleNode("//document/@fontsize")
            _font = New Font(fontNode.Value, Convert.ToSingle(fontSizeNode.Value))
        End Sub

        Private Function PrintPageNumber(ByVal bounds As Rectangle, ByVal top As Integer) As Integer
            Dim format As New StringFormat() With {.Alignment = StringAlignment.Far}
            Dim pagenumber As String = _pageNumber.ToString()
            _gdiPage.DrawString(pagenumber, Font, Brushes.Black, LeftMargin + PrintableWidth, top, format)
            Return top + Convert.ToInt32(_gdiPage.MeasureString(pagenumber, Font).Height)
        End Function

#End Region

    End Class

End Namespace
